import Link from "next/link"; import type { Metadata } from "next"; import { notFound } from "next/navigation"; import { Bar, Chip, Flag, PageHeader, Panel, Stat, Table, Td } from "@/components/ui"; import { api } from "@/lib/api"; import { fmtInt, fmtPct, relTime } from "@/lib/format"; export const dynamic = "force-dynamic"; export async function generateMetadata({ params }: { params: Promise<{ sector: string }> }): Promise { const { sector } = await params; const c = await api.coverageSector(sector); if (!c) return { title: "Coverage" }; return { title: `${c.label} · coverage ${c.score.toFixed(1)}`, description: `${fmtInt(c.covered)} of ${fmtInt(c.members)} ${c.label.toLowerCase()} organizations observed by WebSensor (${c.universes.length} universes).`, alternates: { canonical: `/coverage/${c.sector}` } }; } function band(score: number): string { return score >= 80 ? "text-signal" : score >= 60 ? "text-high" : score >= 40 ? "text-warn" : "text-fg-muted"; } type Params = { u?: string; status?: string }; export default async function CoverageSectorPage({ params, searchParams }: { params: Promise<{ sector: string }>; searchParams: Promise }) { const { sector } = await params; const sp = await searchParams; const c = await api.coverageSector(sector); if (!c) notFound(); const universes = sp.u ? c.universes.filter((u) => u.key === sp.u) : c.universes; const filter = (m: { covered: boolean; shadow: number; seed_status: string | null }): boolean => { if (sp.status === "observed") return m.covered; if (sp.status === "shadow") return !m.covered && m.shadow > 0; if (sp.status === "queued") return !m.covered && m.shadow === 0 && (m.seed_status === "queued" || m.seed_status === "discovering"); if (sp.status === "missing") return !m.covered && m.shadow === 0 && !(m.seed_status === "queued" || m.seed_status === "discovering"); return true; }; const href = (patch: Params): string => { const n = { ...sp, ...patch }; const q = new URLSearchParams(); if (n.u) q.set("u", n.u); if (n.status) q.set("status", n.status); const s = q.toString(); return `/coverage/${c.sector}${s ? `?${s}` : ""}`; }; return ( <> Coverage} title={{c.label} {c.score.toFixed(1)}} description={`${c.description ?? ""} ${fmtInt(c.covered)} of ${fmtInt(c.members)} organizations observed · breadth ${fmtPct(c.breadth)} · depth ${fmtPct(c.depth)} · ${fmtInt(c.sensors)} sensors matched · ${fmtInt(c.shadow_members)} in shadow · ${fmtInt(c.queued)} queued for discovery. Updated ${relTime(c.generated_at)}.`} />
{c.score.toFixed(1)}} hint={`weight ×${c.weight}`} /> x.country !== "—").length)} hint={`${c.universes.length} universes`} />
status {[["", "all"], ["observed", "observed"], ["shadow", "shadow"], ["queued", "queued"], ["missing", "not yet seeded"]].map(([k, l]) => ( {l} ))} · universe all {c.universes.map((u) => ( {u.label} {u.covered}/{u.members} ))}
{universes.map((u) => { const items = u.items.filter(filter); return ( {u.label} {u.score.toFixed(1)} · {u.covered}/{u.members} observed · {fmtInt(u.sensors)} sensors} action={u.provenance ? {u.provenance} : undefined}> {items.length === 0 ? (
No member matches this filter.
) : (
{items.map((m) => ( ))}
{m.source_id ? {m.name} : {m.name}} {m.domain} {m.country ? {m.country} : —} {m.importance} {m.covered ? observed : m.shadow > 0 ? shadow ×{m.shadow} : m.seed_status === "queued" || m.seed_status === "discovering" ? {m.seed_status} : m.seed_status === "blocked" ? blocked : m.seed_status ? {m.seed_status} : not seeded} {m.sensors}{m.shadow ? +{m.shadow} : null}
= 0.8 ? "signal" : m.depth >= 0.4 ? "mid" : "info"} />
{m.source_id && source →}
)}
); })} ); }